package com.nowoe.core.bean;

import com.nowoe.core.annotation.ComponentScan;
import com.nowoe.core.exception.ClassScanException;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 倚栏听风 2023/9/16 10:16
 */
public class BeanFactoryImpl implements BeanFactory {

    private Map<Class<?>, Object> classMap = new ConcurrentHashMap<>();
    private List<BeanPostProcessor> postProcessors = new ArrayList<>();

    public BeanFactoryImpl(Class<?> config, BeanPostProcessor... processors) {
        //添加postProcessors
        postProcessors.addAll(List.of(processors));
        //自动扫描
        if (config.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScan = config.getAnnotation(ComponentScan.class);
            String packageName = componentScan.value();
            String[] strings = packageName.split(",");
            for (String name : strings) {
                try {
                    ComponentScanner.scan(this, name);
                } catch (ClassNotFoundException e) {
                    throw new ClassScanException("类扫描失败：" + e);
                }
            }
            //后置增强
            for (BeanPostProcessor postProcessor : postProcessors) {
                classMap.values().forEach(bean -> postProcessor.enhance(this, bean));
            }

        }

    }


    @Override
    public void register(Class<?> aClass) {
        try {
            if (aClass.isInterface()) {
                classMap.put(aClass, aClass.getName());
            } else {
                Object instance = aClass.getDeclaredConstructor().newInstance();
                if (aClass.getInterfaces().length == 0) {
                    classMap.put(aClass, instance);
                } else {
                    classMap.put(aClass.getInterfaces()[0], instance);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public <T> T getBean(Class<T> aClass) {
        Object obj = classMap.get(aClass);
        return aClass.cast(obj);
    }

    @Override
    public void replace(Class<?> aClass, Object proxyInstance) {
        classMap.put(aClass, proxyInstance);
    }

    @Override
    public Map<Class<?>, Object> getClassMap() {
        return classMap;
    }

    @Override
    public void addPostProcessor(BeanPostProcessor postProcessor) {
        classMap.values().forEach(bean -> postProcessor.enhance(this, bean));
        postProcessors.add(postProcessor);
    }


}
